package org.kommii.encryption;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;



public class RSAHandler {
	
	 /**
     * 生成RSA密钥对(默认密钥长度1024)
     * 
     * @return
     */
    public static KeyPair generateRSAKeyPair() {
        return generateRSAKeyPair(1024);
    }

    /**
     * 生成RSA密钥
     * 
     * @param keyLength
     *            密钥长度，范围：512-2048
     * @return
     */
    public static KeyPair generateRSAKeyPair(int keyLength) {
        try {
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
            kpg.initialize(keyLength);
            return kpg.genKeyPair();
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }
	
    /**
     * 将公钥编码成字符
     * @param key
     * @return
     */
    public static String encodePublicKeyToString(PublicKey key) {
        if (!RSAPublicKey.class.isInstance(key)) {
            return null;
        }
        RSAPublicKey pubKey = (RSAPublicKey) key;
        StringBuilder sb = new StringBuilder();

        sb.append(Base64Helper.encode(pubKey.getModulus().toByteArray())).append(" ");
        sb.append(Base64Helper.encode(pubKey.getPublicExponent().toByteArray()));
        return sb.toString();
    }
    
    /**
     * 将字符创还原为公钥对
     * @param str
     * @return
     */
    public static PublicKey decodePublicKeyFromString(String str) {
        String[] arr = str.split(" ");
        BigInteger modulus = new BigInteger(1, Base64Helper.decode(arr[0]));
        BigInteger publicExponent = new BigInteger(1,Base64Helper.decode(arr[1]));

        RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus,publicExponent);

        KeyFactory keyf;
        try {
            keyf = KeyFactory.getInstance("RSA");
            return keyf.generatePublic(rsaPubKey);
        } catch (Exception e) {
            return null;
        }
    }
    
    /**
     * 将私钥转换成一个map
     * @param key
     * @return
     */
    public static Map encodePrivateKeyToMap(PrivateKey key) {
    	Map map = new HashMap();
        if (!RSAPrivateCrtKey.class.isInstance(key)) {
            return null;
        }
        RSAPrivateCrtKey priKey = (RSAPrivateCrtKey) key;
        //StringBuilder sb = new StringBuilder();
       
        String modulus = Base64Helper.encode(priKey.getModulus().toByteArray());
       
        String publicExponent = Base64Helper.encode(priKey.getPublicExponent().toByteArray());
        
        String primeP = Base64Helper.encode(priKey.getPrimeP().toByteArray());
        
        String primeQ = Base64Helper.encode(priKey.getPrimeQ().toByteArray());
        
        String primeExponentP = Base64Helper.encode(priKey.getPrimeExponentP().toByteArray());
        
        String primeExponentQ = Base64Helper.encode(priKey.getPrimeExponentQ().toByteArray());
       
        String crtCoefficient = Base64Helper.encode(priKey.getCrtCoefficient().toByteArray());
        
        String privateExponent = Base64Helper.encode(priKey.getPrivateExponent().toByteArray());
        
        map.put("modulus", modulus);
        map.put("publicExponent", publicExponent);
        map.put("primeP", primeP);
        map.put("primeQ", primeQ);
        map.put("primeExponentP", primeExponentP);
        map.put("primeExponentQ", primeExponentQ);
        map.put("crtCoefficient", crtCoefficient);
        map.put("privateExponent", privateExponent);
        return map;
    }
    
    /**
     * 将map 转换为一个私钥对
     * @param map
     * @return
     */
    public static PrivateKey decodePrivateKeyFromMap(Map map) {
    	
    	 BigInteger modulus = new BigInteger(1, Base64Helper.decode((String)map.get("modulus")));
         
    	 BigInteger publicExponent = new BigInteger(1, Base64Helper.decode((String)map.get("publicExponent")));
         
    	 BigInteger primeP = new BigInteger(1, Base64Helper.decode((String)map.get("primeP")));
         
    	 BigInteger primeQ = new BigInteger(1, Base64Helper.decode((String)map.get("primeQ")));
         
    	 BigInteger primeExponentP = new BigInteger(1, Base64Helper.decode((String)map.get("primeExponentP")));
         
    	 BigInteger primeExponentQ = new BigInteger(1, Base64Helper.decode((String)map.get("primeExponentQ")));
        
    	 BigInteger crtCoefficient = new BigInteger(1, Base64Helper.decode((String)map.get("crtCoefficient")));
         
    	 BigInteger privateExponent = new BigInteger(1, Base64Helper.decode((String)map.get("privateExponent")));
         
        RSAPrivateCrtKeySpec rsaPriKey = new RSAPrivateCrtKeySpec(modulus,
                publicExponent, privateExponent, primeP, primeQ,
                primeExponentP, primeExponentQ, crtCoefficient);

        KeyFactory keyf;
        try {
            keyf = KeyFactory.getInstance("RSA");
            return keyf.generatePrivate(rsaPriKey);
        } catch (Exception e) {
            return null;
        }
    }
    
    

    
    /**
     * 用公钥加密
     * @param data
     * @param pubKey
     * @return
     */
    public static byte[] encryptDataByPubKey(byte[] data, PublicKey pubKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            return cipher.doFinal(data);
        } catch (Exception e) {
            return null;
        }
    }
    
    /**
     * 用公钥解密
     * @param data
     * @param pubKey
     * @return
     */
    public static byte[] decryptDataByPubKey(byte[] data, PublicKey pubKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, pubKey);
            return cipher.doFinal(data);
        } catch (Exception e) {
            return null;
        }
    }
    
    
    /**
     *  用私钥加密
     * @param encryptedData
     * @param priKey
     * @return
     */
    public static byte[] encryptDataByPriKey(byte[] encryptedData, PrivateKey priKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, priKey);
            return cipher.doFinal(encryptedData);
        } catch (Exception e) {
            return null;
        }
    }


    /**
     *  用私钥解密
     * @param encryptedData
     * @param priKey
     * @return
     */
    public static byte[] decryptDataByPriKey(byte[] encryptedData, PrivateKey priKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            return cipher.doFinal(encryptedData);
        } catch (Exception e) {
            return null;
        }
    }
    
    
    /**
     * 根据指定私钥对数据进行签名(默认签名算法 "SHA1withRSA")
     * 
     * @param data
     *            要签名的数据
     * @param priKey
     *            私钥
     * @return
     */
    public static byte[] signData(byte[] data, PrivateKey priKey) {
        return signData(data, priKey, "SHA1withRSA");
    }

    /**
     * 根据指定私钥和算法对数据进行签名
     * 
     * @param data
     *            要签名的数据
     * @param priKey
     *            私钥
     * @param algorithm
     *            签名算法
     * @return
     */
    public static byte[] signData(byte[] data, PrivateKey priKey,
            String algorithm) {
        try {
            Signature signature = Signature.getInstance(algorithm);
            signature.initSign(priKey);
            signature.update(data);
            return signature.sign();
        } catch (Exception ex) {
            return null;
        }
    }
    
    /**
     * 用指定的公钥进行签名验证(默认签名算法�?"SHA1withRSA")
     * 
     * @param data
     *            数据
     * @param sign
     *            签名结果
     * @param pubKey
     *            公钥
     * @return
     */
    public static boolean verifySign(byte[] data, byte[] sign, PublicKey pubKey) {
        return verifySign(data, sign, pubKey, "SHA1withRSA");
    }

    /**
     * @param data 数据
     * @param sign 签名结果
     * @param pubKey 公钥
     * @param algorithm 签名算法
     * @return
     */
    public static boolean verifySign(byte[] data, byte[] sign,
            PublicKey pubKey, String algorithm) {
        try {
            Signature signature = Signature.getInstance(algorithm);
            signature.initVerify(pubKey);
            signature.update(data);
            return signature.verify(sign);
        } catch (Exception ex) {
            return false;
        }
    }
    
    

    
    public static void main(String[] args){
    	long begin=System.currentTimeMillis();
    	KeyPair kp = generateRSAKeyPair(512);
    	String str = encodePublicKeyToString(kp.getPublic());
    	//System.out.println(str);
    	PublicKey pubk2 = decodePublicKeyFromString(str);
    	Map map = encodePrivateKeyToMap(kp.getPrivate());
    	PrivateKey prik2 = decodePrivateKeyFromMap(map);
    	/*
    	PublicKey pubk = kp.getPublic();
    	PrivateKey prik = kp.getPrivate();
    	*/
    	
    	long temp = System.currentTimeMillis();
		long now = temp/1000;
		//System.out.println(temp);
		//System.out.println(now);
    	Map m = new HashMap();
    	m.put("t", "test");
    	m.put("time", new Date());
    	m.put("name", "地方");
    	//String ss = "2015-02-15 15:09:12";
    	String ss = "估计还感觉很好规范将合格合格后";
		String s = String.valueOf(now);
		
		System.out.println(ss);
    	//String s = "235yd@f@&%hjht我没收到过副本伤@风败俗�??/r43tergfrg";
    	byte[] by = ss.getBytes();
    	
    	byte[] rs =  encryptDataByPubKey(by,pubk2);
    	//byte[] rs = decryptDataByPriKey(by,prik2);
    	System.out.println(new String(rs));
    	
    	//String temp2 = Base64Helper.encode(rs);
		//System.out.println(temp2);
		//byte[] rs2 = Base64Helper.decode(temp2);
		byte[] ders = decryptDataByPriKey(rs,prik2);
    	//byte[] rs =  encryptDataByPriKey(by,prik2);
    	//byte[] ders = decryptDataByPubKey(rs,pubk2);
    	//System.out.println(new String(rs));
    	System.out.println(new String(ders));
    	
    	
    	/*System.out.println(kp.getPublic());
    	System.out.println(str);
    	
    	System.out.println(pubk2);
    	
    	
    	System.out.println(kp.getPrivate());
    	System.out.println("-------------");
    	
    	System.out.println(prik2);
    	*/
    	//私钥签名
    	// byte[] signDataByteArray = signData(by, prik2);
         // 验签
        // boolean isMatch = verifySign(ders,signDataByteArray, pubk2);
        // System.out.println("验签结果�?" + isMatch);
    	long end = System.currentTimeMillis();
		System.out.println("time"+(end-begin));
	
    }

}
